﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

using Core;
using Core.Utility;
using Core.Settings;
using Core.Model;
using Core.Exceptions;
using Core.Enumerations;
using System.Collections;
using Core.Events;
using Session;
using System.Text.RegularExpressions;
using System.Xml;

namespace RandomNetworksExplorer
{
    public partial class StructuralAnalysis : Form
    {
        private static List<Guid> researchIDs = new List<Guid>();

        public StructuralAnalysis()
        {
            InitializeComponent();
        }

        private Boolean GetSubGraphs(out Dictionary<int, int[]> subGraphs)
        {
            String content;
            String[] components;
            Boolean isGroup = false;
            Boolean isInterval = false;
            int delimiterCount = 0;

            subGraphs = new Dictionary<int, int[]>();

            content = File.ReadAllText(inputSubgraphsName.Text);

            /* Replace all whitespaces */
            content = Regex.Replace(content, @"\s+", "");

            /* Determine the type of components based on brackets' type: groups{} or intervals[] */
            if ((delimiterCount = content.Count(c => c == '[')) ==
                content.Count(c => c == ']') &&
                0 != delimiterCount)
            {
                isInterval = true;
            }

            if ((delimiterCount = content.Count(c => c == '{')) ==
                content.Count(c => c == '}') &&
                0 != delimiterCount)
            {
                isGroup = true;
            }

            if (isInterval == isGroup)
            {
                return false;
            }

            /* All components should be separated by ';' symbol. */
            components = content.Split(';');

            for (int i = 0; i < components.Count(); ++i)
            {
                /* Get the certain component and validate it. */
                MatchCollection matchedItems = Regex.Matches(components[i],
                                            isInterval ? @"(?<=\[)(.*?)(?=\])" :
                                            @"(?<=\{)(.*?)(?=\})");
                if (1 != matchedItems.Count ||
                    !Regex.IsMatch(matchedItems[0].ToString(), @"^[0-9\,]+$"))
                {
                    return false;
                }

                String[] elements = matchedItems[0].ToString().Split(',');
                /* For intervals the number of elements should be 2 */
                if (isInterval && 2 != elements.Count())
                {
                    return false;
                }

                /* All elements should be integers. */
                for (int j = 0, intVal; j < elements.Count(); ++j)
                {
                    if (!int.TryParse(elements[j], out intVal))
                    {
                        return false;
                    }
                }

                if (isInterval)
                {
                    int val1, val2;

                    int.TryParse(elements[0], out val1);
                    int.TryParse(elements[1], out val2);

                    if (val1 >= val2)
                    {
                        return false;
                    }
                }
            }

            if (isInterval)
            {
                /* Create subgraphs from given intervals. */
                for (int i = 0; i < components.Count(); ++i)
                {
                    int [] interval = components[i].Replace("[", "").Replace("]", "").Split(',').Select(int.Parse).ToArray();
                    int [] group = new int[interval[1] - interval[0] + 1];
                    for (int j = interval[0], k = 0; j < interval[1]; ++j, k++)
                    {
                        group[k] = j;
                    }
                    subGraphs.Add(i, group);
                }
            }
            else
            {
                /* Create subgraphs from given groups. */
                for (int i = 0; i < components.Count(); ++i)
                {
                    subGraphs.Add(i, components[i].Replace("{", "").Replace("}", "").Split(',').Select(int.Parse).ToArray());
                }
            }

            return true;
        }

        private int outerConnectionsCount(ArrayList graphMatrix, int[] subGraph1, int[] subGraph2)
        {
            int connectionCount = 0;
            int[] newSubgraph = new int[subGraph1.Count() + subGraph2.Count()];
            Array.Copy(subGraph1, newSubgraph, subGraph1.Count());
            Array.Copy(subGraph2, 0, newSubgraph, subGraph1.Count(), subGraph2.Count());

            ArrayList curMatrix = createClassicalMatrix(graphMatrix, newSubgraph);

            for (int i = 0; i < subGraph1.Count(); ++i)
            {
                for (int p = 0; p < subGraph1.Count() + subGraph2.Count(); ++p)
                {
                    if (i < subGraph1.Count() && p >= subGraph1.Count())
                    {
                        if ((bool)(((ArrayList)curMatrix[i])[p]))
                        {
                            connectionCount++;
                        }
                    }
                }
            }

            return connectionCount;
        }

        private void convert_Click(object sender, EventArgs e)
        {
            EnableControls(false);

            int size = int.Parse(sizeTxt.Text.ToString());
            try
            {
                MatrixInfoToRead matrix = FileManager.Read(inputFileNameTxt.Text, size, AdjacencyMatrixType.ClassicalMatrix);

                int newRowIndex = statusTable.Rows.Add();
                statusTable.Rows[newRowIndex].Cells["statusStatusColumn"].Value = "Not Started.";
                statusTable.Rows[newRowIndex].Cells["statusStopColumn"].Value = "Stop";

                Dictionary<int, int[]> subGraphs;

                if (GetSubGraphs(out subGraphs))
                {
                    for (int i = 0; i < subGraphs.Count; ++i)
                    {
                        for (int j = 0; j < subGraphs[i].Count(); ++j)
                        {
                            if (subGraphs[i][j] >= size)
                            {
                                MessageBox.Show("Input subgraphs format is not correct.", "Error");
                                return;
                            }
                        }
                    }
                }
                else
                {
                    MessageBox.Show("Input subgraphs format is not correct.", "Error");
                    return;
                }

                int l = inputFileNameTxt.Text.Length;
                int last = inputFileNameTxt.Text.Substring(0, l - 4).LastIndexOf("\\") + 1;

                for (int i = 0; i < subGraphs.Count; ++i)
                {
                    MatrixInfoToRead curMatrix = new MatrixInfoToRead();
                    curMatrix.Matrix = createClassicalMatrix(matrix.Matrix, subGraphs[i]);

                    Guid id = SessionManager.CreateResearch(ResearchType.Basic);
                    SessionManager.AddResearchUpdateHandler(id, CurrentResearch_OnResearchUpdateStatus);
                    SessionManager.AddResearchEnsembleUpdateHandler(id, CurrentResearch_OnResearchEnsembleUpdateStatus);
                    SessionManager.SetResearchModelType(id, ModelType.ER); /* FIXME */
                    SessionManager.SetResearchGenerationType(id, GenerationType.Static);

                    SessionManager.SetResearchStorage(id, StorageType.XMLStorage, ExplorerSettings.StorageDirectory);

                    SessionManager.SetResearchName(id, inputFileNameTxt.Text.Substring(0, l - 4).Substring(last, l - 4 - last) + "_" + i);
                    SessionManager.SetResearchTracingPath(id, ExplorerSettings.TracingDirectory);
                    SessionManager.SetGenerationParameterValue(id, GenerationParameter.AdjacencyMatrix, curMatrix);
                    /* FIXME: Should we set this param value?? */
                    SessionManager.SetGenerationParameterValue(id, GenerationParameter.AdjacencyMatrixFile, curMatrix);
                    SessionManager.SetResearchRealizationCount(id, 1);
                    SessionManager.SetAnalyzeOptions(id, SessionManager.GetAvailableAnalyzeOptions(id));
                    SessionManager.StartResearch(id);
                }

                /* Calculate and save outer connections count. */
                {
                    int outerConnectionCount = 0;
                    for (int i = 0; i < subGraphs.Count; ++i)
                    {
                        for (int j = i + 1; j < subGraphs.Count; ++j)
                        {
                            outerConnectionCount += outerConnectionsCount(matrix.Matrix, subGraphs[i], subGraphs[j]);
                        }
                    }

                    string filePath = ExplorerSettings.StorageDirectory + "\\";
                    filePath  += inputFileNameTxt.Text.Substring(0, l - 4).Substring(last, l - 4 - last) +
                        "_" + subGraphs.Count;
                    if (File.Exists(filePath + ".xml"))
                    {
                        filePath += Guid.NewGuid();
                    }

                    using (XmlWriter writer = XmlWriter.Create(filePath + ".xml"))
                    {
                        writer.WriteStartDocument(true);
                        writer.WriteStartElement("StructuralAnalysis");

                        writer.WriteElementString("OuterConnectionCount", outerConnectionCount.ToString());

                        writer.WriteEndElement();
                    }
                }
            }


            catch (MatrixFormatException)
            {
                MessageBox.Show("Input matrix format is not correct.", "Error");
                inputFileNameTxt.Focus();
                inputFileNameTxt.SelectAll();
                return;
            }


            finally
            {
                EnableControls(true);
            }
        }

        /* Create matrix from given graph matrix and subgraph members. */
        ArrayList createClassicalMatrix(ArrayList inMatrix, int[] subgraph)
        {
            ArrayList matrix = new ArrayList();
            {
                for (int j = 0; j < subgraph.Count(); ++j)
                {
                    ArrayList tmp = new ArrayList();
                    for (int k = 0; k < subgraph.Count(); ++k)
                    {
                        if ((bool)((ArrayList)inMatrix[subgraph[j]])[subgraph[k]])
                        {
                            tmp.Add(true);
                        }
                        else
                        {
                            tmp.Add(false);
                        }
                    }

                    matrix.Add(tmp);
                }
            }

            return matrix;
        }
        private void EnableControls(bool b)
        {
            inputFileNameTxt.Enabled = b;
            inputBrowse.Enabled = b;
            sizeTxt.Enabled = b;
            degreesRadioBtn.Enabled = b;
            csvRadioBtn.Enabled = b;
            outputFileNameTxt.Enabled = b;
            outputBrowse.Enabled = b;
            convert.Enabled = b;
        }

        private void CurrentResearch_OnResearchUpdateStatus(object sender, ResearchEventArgs e)
        {
            statusTable.Rows[0].Cells["statusStatusColumn"].Value = e.Status.ToString();
        }

        private void CurrentResearch_OnResearchEnsembleUpdateStatus(object sender, ResearchEnsembleEventArgs e)
        {
            statusTable.Rows[e.UpdatedNetworkID].Cells["statusStatusColumn"].Value = e.UpdatedExtendedInfo;
        }

        private void inputBrowse_Click(object sender, EventArgs e)
        {
            openFileDlg.InitialDirectory = ExplorerSettings.MatrixConvertionToolDirectory;
            if (openFileDlg.ShowDialog() == DialogResult.OK)
            {
                ExplorerSettings.MatrixConvertionToolDirectory = Path.GetDirectoryName(openFileDlg.FileName);
                ExplorerSettings.Refresh();
                inputFileNameTxt.Text = openFileDlg.FileName;
                int l = inputFileNameTxt.Text.Length;
                outputFileNameTxt.Text = inputFileNameTxt.Text.Substring(0, l - 4) + "_out.txt";
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            openFileDlg.InitialDirectory = ExplorerSettings.MatrixConvertionToolDirectory;
            if (openFileDlg.ShowDialog() == DialogResult.OK)
            {
                ExplorerSettings.MatrixConvertionToolDirectory = Path.GetDirectoryName(openFileDlg.FileName);
                ExplorerSettings.Refresh();
                inputSubgraphsName.Text = openFileDlg.FileName;
            }
        }

        private void outputBrowse_Click(object sender, EventArgs e)
        {
            saveFileDlg.InitialDirectory = ExplorerSettings.MatrixConvertionToolDirectory;
            saveFileDlg.FileName = outputFileNameTxt.Text;
            if (saveFileDlg.ShowDialog() == DialogResult.OK)
            {
                outputFileNameTxt.Text = saveFileDlg.FileName;
            }
        }

        private void inputSubgraphsName_TextChanged(object sender, EventArgs e)
        {

        }
    }
}
